package com.company.cloud.coupon.modules.app.service.impl;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.company.cloud.common.bean.BaseClientResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.company.cloud.common.asserts.ValidatorUtils;
import com.company.cloud.common.bean.LoginSimpleUserInfo;
import com.company.cloud.common.bean.LoginUserInfo;
import com.company.cloud.common.constant.BaseConstant.EnabledEnum;
import com.company.cloud.common.constant.BaseConstant.YNEnum;
import com.company.cloud.common.constant.BaseReturnEnum;
import com.company.cloud.common.exception.BusinessException;
import com.company.cloud.common.utils.LocalDateTimeUtils;
import com.company.cloud.common.utils.StrSplitUtils;
import com.company.cloud.coupon.constant.CouponConstant.CouponConfigTypeEnum;
import com.company.cloud.coupon.constant.CouponConstant.CouponEndDateTypeEnum;
import com.company.cloud.coupon.constant.CouponConstant.CouponGetType;
import com.company.cloud.coupon.constant.CouponConstant.CouponStateEnum;
import com.company.cloud.coupon.constant.CouponConstant.CouponUsableObjTypeEnum;
import com.company.cloud.coupon.constant.CouponConstant.CouponUserObjType;
import com.company.cloud.coupon.constant.CouponErrorEnum;
import com.company.cloud.coupon.modules.api.request.CouponOrderItem;
import com.company.cloud.coupon.modules.app.controller.req.CouponListByOrderParam;
import com.company.cloud.coupon.modules.app.controller.req.OrderProductItem;
import com.company.cloud.coupon.modules.app.service.CouponService;
import com.company.cloud.coupon.modules.base.entity.CouponConfigInfo;
import com.company.cloud.coupon.modules.base.entity.CouponInfo;
import com.company.cloud.coupon.modules.base.service.CouponConfigInfoService;
import com.company.cloud.coupon.modules.base.service.CouponInfoService;
import com.company.cloud.coupon.modules.cache.models.CouponModel;
import com.company.cloud.coupon.modules.cache.utils.CouponChangeUtils;
import com.company.cloud.coupon.modules.mgr.controller.req.CouponSendParam;
import com.company.cloud.coupon.modules.mgr.controller.req.CouponUseParam;
import com.company.cloud.coupon.utils.OpCouponUtils;
import com.company.cloud.product.modules.api.response.Sku;
import com.company.cloud.product.modules.api.service.ProductRemoteService;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;

@Service
public class CouponServiceImpl implements CouponService{
	
	
	@Autowired
	private CouponConfigInfoService couponConfigInfoService;
	@Autowired
	private CouponInfoService couponInfoService;
	@Autowired
	private ProductRemoteService productRemoteService;

	
	private BigDecimal getRandomCouponFund(BigDecimal minFund,BigDecimal maxFund, boolean isMaxFund) {
		if(isMaxFund) {
			return maxFund;
		}
		return	RandomUtil.randomBigDecimal(minFund, maxFund).setScale(2, BigDecimal.ROUND_FLOOR);
	}
	
	private CouponInfo getCouponEntity(CouponConfigInfo couponConfig,Integer userId ,String remark,
			String relType, Integer relId, boolean isMaxFund,LoginSimpleUserInfo userInfo) {
		CouponInfo entity=new CouponInfo();
		entity.setCouponNo(OpCouponUtils.getCouponNo());
		entity.setCouponConfigId(couponConfig.getId());
		entity.setCompanyNo(couponConfig.getCompanyNo());
		entity.setSourceBizType(relType);
		entity.setSourceBizId(relId);
		entity.setCouponCode(OpCouponUtils.getCouponNo());
		entity.setTitle(couponConfig.getTitle());
		entity.setIsUseLimit(couponConfig.getIsUseLimit());
		entity.setUseFullFund(couponConfig.getUseFullFund());
		
		entity.setCouponType(couponConfig.getCouponType());
		if(CouponConfigTypeEnum.Random_Cash_Coupon.getCode().equals(couponConfig.getCouponType())) {
			entity.setCouponFund(this.getRandomCouponFund(couponConfig.getCouponFund(),
					couponConfig.getCouponFundMax(),isMaxFund));
		}else {
			entity.setCouponFund(couponConfig.getCouponFund());
		}
		
		entity.setIsMaxDisFund(couponConfig.getIsMaxDisFund());
		entity.setMaxDisFund(couponConfig.getMaxDisFund());
		entity.setUsableObjType(couponConfig.getUsableObjType());
		entity.setUsableObjNo(couponConfig.getUsableObjNo());
		entity.setIsRemind(couponConfig.getIsRemind());
		entity.setRemindDay(couponConfig.getRemindDay());
		entity.setOtherSetting(couponConfig.getOtherSetting());
		entity.setShareSetting(couponConfig.getShareSetting());
		entity.setHaveDate(LocalDateTime.now());
		entity.setHaveUserId(userId);
		entity.setHaveIp(userInfo.getIp());
		
		if(CouponEndDateTypeEnum.Appointed_EndDate.getCode().equals(couponConfig.getUseDateType())) {
			entity.setStartDate(couponConfig.getUseStartDate());
			entity.setEndDate(couponConfig.getUseEndDate());
		}else {
			entity.setStartDate(LocalDateTime.now());
			entity.setEndDate(LocalDateTimeUtils.plusDay(LocalDateTime.now(), couponConfig.getUseEndDay()));
		}
		entity.setState(CouponStateEnum.Not_CouponState.getCode());
//		entity.setusableDate
//		entity.setusableIp
//		entity.setrelIdType
//		entity.setrelId
		entity.setRemark(remark);
		entity.addCreateParam(userInfo);
		entity.addEditParam(userInfo);
		return entity;
	}
	/**单个用户发优惠券*/
	private Map<Integer, CouponInfo> addCoupon(CouponConfigInfo couponConfig,Integer userId,String remark,
			String relType, Integer relId, boolean isMaxFund,LoginSimpleUserInfo userInfo) {
		List<Integer> userIds=new ArrayList<Integer>();
		userIds.add(userId);
		Map<Integer, CouponInfo> result= this.addCoupon(couponConfig, userIds, remark,relType,relId,isMaxFund, userInfo);
		return result;
	}
	
	/**多个用户发优惠券*/
	private Map<Integer, CouponInfo> addCoupon(CouponConfigInfo couponConfig,List<Integer> userIds,String remark,
			String relType, Integer relId, boolean isMaxFund,LoginSimpleUserInfo userInfo) {
		//优惠券总数量限制
		if(YNEnum.YES.getCode().equals(couponConfig.getTotalNumType())) { 
			int num= couponInfoService.count(new QueryWrapper<CouponInfo>()
					 .eq("coupon_config_id", couponConfig.getId()));
			num=num+userIds.size();
			if(num>couponConfig.getTotalNum()) {
				throw new BusinessException("优惠券已经领取完");
			}
		}
		
		List<CouponInfo> couponList=new ArrayList<CouponInfo>();
		Map<Integer, CouponInfo> resultMap=new HashMap<Integer, CouponInfo>();
		for(Integer userId:userIds) {
			//优惠券会员领取数量限制
			if(CouponGetType.CFG_Act_Num.getCode().equals(couponConfig.getMemberGetNumType())) {
				 int num= couponInfoService.count(new QueryWrapper<CouponInfo>()
						 .eq("coupon_config_id", couponConfig.getId())
						 .eq("have_user_id", userId));
				 if(num>=couponConfig.getMemberGetNum()) {
					 throw new BusinessException(CouponErrorEnum.CouponFission_GiveNum);
				 }
			}else if(CouponGetType.CFG_Day_Num.getCode().equals(couponConfig.getMemberGetNumType())) {
				 int num= couponInfoService.count(new QueryWrapper<CouponInfo>()
						 .eq("coupon_config_id", couponConfig.getId())
						 .eq("have_user_id", userId)
						 .eq("date_format(have_date ,'%Y-%m-%d' )", DateUtil.formatDate(new Date()))
						 );
				 if(num>=couponConfig.getMemberGetNum()) {
					 throw new BusinessException(CouponErrorEnum.CouponFission_GiveNum);
				 }
			}
			CouponInfo entity= this.getCouponEntity(couponConfig, userId, remark,relType,relId,isMaxFund, userInfo);
			couponList.add(entity);
			resultMap.put(userId, entity);
		}
		if(couponList.size()>0) {
			couponInfoService.saveBatch(couponList);
		}
		return resultMap;
	}
	
	/**领取优惠券*/
	@Override
	public CouponInfo collectCoupon(Integer userId, Integer couponConfigId,LoginSimpleUserInfo userInfo) {
		return this.collectCoupon(userId, couponConfigId, null, null, false, userInfo);
	}
	
	
	@Override
	public CouponInfo collectCoupon(Integer userId, Integer couponConfigId, String relType, 
			Integer relId, boolean isMaxFund,LoginSimpleUserInfo userInfo) {
		CouponConfigInfo  couponConfig= couponConfigInfoService.getById(couponConfigId);
		if(couponConfig==null || EnabledEnum.DISABLED.getCode().equals(couponConfig.getRowsState())) {
			throw new BusinessException(BaseReturnEnum.DATA_NOT_EXISTS);
		}
		if(YNEnum.NO.getCode().equals(couponConfig.getUpperLowerState())) {
			throw new BusinessException("优惠券未上架");
		}
		if(YNEnum.YES.getCode().equals(couponConfig.getMemberUseType())) {
			throw new BusinessException("用户领取限制");
		}
		Map<Integer, CouponInfo> resultMap=this.addCoupon(couponConfig, userId, null,relType,relId,isMaxFund, userInfo);
		return resultMap==null?null:resultMap.get(userId);
	}
	
	
	
	/**发放优惠券*/
	@Override
	public void sendCoupon(CouponSendParam params, LoginSimpleUserInfo userInfo) {
		ValidatorUtils.validate(params);
		CouponConfigInfo  couponConfig= couponConfigInfoService.getById(params.getCouponConfigId());
		if(couponConfig==null || EnabledEnum.DISABLED.getCode().equals(couponConfig.getRowsState())) {
			throw new BusinessException(BaseReturnEnum.DATA_NOT_EXISTS);
		}
		if(YNEnum.NO.getCode().equals(couponConfig.getUpperLowerState())) {
			throw new BusinessException("优惠券未上架");
		}
		if(YNEnum.YES.getCode().equals(couponConfig.getMemberUseType())) {
			throw new BusinessException("用户领取限制");
		}
		if(CouponUserObjType.User_CouponObj.getCode().equals(params.getSendObjType())) {
			this.addCoupon(couponConfig, Integer.parseInt(params.getSendObj()), params.getRemark(),
					null,null,false,userInfo);
		}
	}

	/**使用优惠券*/
	@Override
	public void useCouponByScan(CouponUseParam params, LoginSimpleUserInfo userInfo) {
		ValidatorUtils.validate(params);
		CouponInfo coupon=couponInfoService.getById(params.getCouponNo());
		if(coupon==null) {
			throw new BusinessException(CouponErrorEnum.Coupon_Null);
		}
		if(CouponStateEnum.Not_CouponState.getCode().equals(coupon.getState())) {
			throw new BusinessException(CouponErrorEnum.Coupon_Use);
		}
		if(LocalDateTimeUtils.compare(coupon.getStartDate(), LocalDateTime.now())>0) {
			throw new BusinessException(CouponErrorEnum.Coupon_StartDate);
		}
		if(LocalDateTimeUtils.compare(coupon.getEndDate(), LocalDateTime.now())<0) {
			throw new BusinessException(CouponErrorEnum.Coupon_EndDate);
		}
		coupon.setState(CouponStateEnum.Yes_Scan_CouponState.getCode());
		coupon.setUsableDate(LocalDateTime.now());
		coupon.setUsableIp(userInfo.getIp());
		coupon.addEditParam(userInfo);
		couponInfoService.updateById(coupon);
	}
	
	
	/**根据订单查询我可使用的优惠券*/
	@Override
	public List<CouponModel> getMyCouponByOrder(CouponListByOrderParam params,LoginSimpleUserInfo userInfo){
		ValidatorUtils.validate(params);
		List<CouponModel> result=new ArrayList<CouponModel>();
		couponInfoService.update(new UpdateWrapper<CouponInfo>()
				.set("state", CouponStateEnum.Overdue_CouponState.getCode())
				.eq("state", CouponStateEnum.Not_CouponState.getCode())
				.eq("have_user_id", userInfo.getId())
				.lt("end_date", LocalDateTime.now())
				);
		
		List<CouponInfo> couponList=couponInfoService.list(new QueryWrapper<CouponInfo>()
				.eq("have_user_id", userInfo.getId())
				.eq("state", CouponStateEnum.Not_CouponState.getCode())
				.le("start_date", LocalDateTime.now())
				.ge("end_date", LocalDateTime.now())
				);
		
		if(CollectionUtils.isEmpty(couponList)) {
			return result;
		}
		
		Set<String> skuNoSet=new HashSet<String>();
 		params.getItems().forEach(item->{ skuNoSet.add(item.getSkuNo()); });
		BaseClientResult<Map<String, Sku>> skuResp= productRemoteService.getSkuMapByDbByNos(skuNoSet);
		Map<String, Sku> skuMap=BaseClientResult.getResultData(skuResp);
		List<CouponOrderItem> orderItems=new ArrayList<CouponOrderItem>();
		String companyNo=null;
		for(OrderProductItem productItem: params.getItems()) {
			Sku sku= skuMap.get(productItem.getSkuNo());
			if(sku==null) {
				throw new BusinessException("商品不存在");
			}
			if(companyNo==null) {
				companyNo=sku.getCompanyNo();
			}else if(!companyNo.equals(sku.getCompanyNo())) {
				throw new BusinessException("商品商户必须一致");
			}
			
			orderItems.add(new CouponOrderItem(sku.getProductNo(), sku.getSkuNo(), 
					sku.getCategoryId(),sku.getPrice(), productItem.getQuantity()));
		}
		
		couponList.forEach(item->{
			BigDecimal couponFund= this.calCouponFund(item, orderItems);
			if(couponFund!=null && couponFund.doubleValue()>0) {
				CouponModel coupon= CouponChangeUtils.getCoupon(item,null);
				coupon.setDisFund(couponFund);
				result.add(coupon);
			}
		});
		return result;
	}
	
	/**
	 * 计算优惠券使用金额
	 * */
	@Override
	public BigDecimal calCouponFund(CouponInfo coupon ,List<CouponOrderItem> items) {
		
		BigDecimal TotalFund=BigDecimal.ZERO;
		//指定
		if(CouponUsableObjTypeEnum.Appointed_UsableObj.getCode().equals(coupon.getUsableObjType())) {
			Set<String> productNos=new HashSet<String>();
			items.forEach(ordetItem->{productNos.add(ordetItem.getProductNo());});
			Set<String> usableObjNos=StrSplitUtils.parse2set(coupon.getUsableObjNo(), String.class);
			usableObjNos.retainAll(productNos);
			if(usableObjNos.size()<=0) {
				return BigDecimal.ZERO;
			}
			//是否有使用门槛+折扣券，计算符合条件的商品金额
			if(YNEnum.YES.getCode().equals(coupon.getIsUseLimit())
					|| CouponConfigTypeEnum.Discount_Coupon.getCode().equals(coupon.getCouponType())) {
				for(CouponOrderItem item:items) {
					if(usableObjNos.contains(item.getProductNo())) {
						BigDecimal fund= item.getPrice().multiply(new BigDecimal(item.getQuantity()));
						TotalFund=TotalFund.add(fund);
					}
				}
			}
		}else { //所有商品
			//是否有使用门槛+折扣券，计算符合条件的商品金额
			if(YNEnum.YES.getCode().equals(coupon.getIsUseLimit())
					|| CouponConfigTypeEnum.Discount_Coupon.getCode().equals(coupon.getCouponType())) {
				for(CouponOrderItem item:items) {
					BigDecimal fund= item.getPrice().multiply(new BigDecimal(item.getQuantity()));
					TotalFund=TotalFund.add(fund);
				}
			}
		}
		
		
		//是否有使用门槛
		if(YNEnum.YES.getCode().equals(coupon.getIsUseLimit())) {
			if(coupon.getUseFullFund().doubleValue()>TotalFund.doubleValue()) {
				return BigDecimal.ZERO;
			}
		}
		
		if(CouponConfigTypeEnum.Cash_Coupon.getCode().equals(coupon.getCouponType())) {
			//现金券
			return coupon.getCouponFund();
		}else if(CouponConfigTypeEnum.Discount_Coupon.getCode().equals(coupon.getCouponType())) {
			//折扣券
			BigDecimal _couponFund=TotalFund.multiply(coupon.getCouponFund()).divide(new BigDecimal(100))
					.setScale(2, BigDecimal.ROUND_FLOOR);
			if(YNEnum.YES.getCode().equals(coupon.getIsMaxDisFund())) {
				return _couponFund.doubleValue()>coupon.getMaxDisFund().doubleValue()?coupon.getMaxDisFund():_couponFund;
			}else {
				return _couponFund;
			}
		}else if(CouponConfigTypeEnum.Random_Cash_Coupon.getCode().equals(coupon.getCouponType())) {
			//随机金额券
			return coupon.getCouponFund();
		}
		return BigDecimal.ZERO;
	}



	
}
